﻿using System;
using System.Collections.Generic;
using System.Linq;
using EscapeZone.Components;
using EscapeZone.Interfaces;
using EscapeZone.Mapping.Elements;
using EscapeZone.Screens;
using Microsoft.Xna.Framework;

namespace EscapeZone.Mapping
{
    public class Map : DrawableEscapeGameComponent
    {
        public new GameScreen Screen { get { return base.Screen as GameScreen; } }

        public List<IMapElement> MapElements { get; set; }

        public Vector2 SpawnPosition
        {
            get { return MapElements.OfType<Spawn>().First().Position; }
        }
        private readonly GoalZone goalZone;

        public override void Initialize()
        {
            base.Initialize();
            Random rand = new Random();
            for (int i = 0; i < 5; ++i)
            {
                Coin c = new Coin();
                do
                {
                    c.Position = new Vector2((float) rand.NextDouble()*Game.Bounds.Width,
                                             (float) rand.NextDouble()*Game.Bounds.Height);
                } while (IntersectsWall(c.Rect));
                MapElements.Add(c);
            }
        }

        public Map(EscapeGame game, GameScreen screen, IEnumerable<IMapElement> mapElements) : base(game, screen)
        {
            MapElements = new List<IMapElement>();
            MapElements.AddRange(mapElements);

            goalZone = MapElements.OfType<GoalZone>().FirstOrDefault();
        }

        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            List<IMapElement> toRemove = new List<IMapElement>();
            foreach (Coin c in MapElements.OfType<Coin>())
            {
                if (c.Rect.Intersects(Screen.Player.Rect))
                {
                    Screen.Player.Score += 10;
                    toRemove.Add(c);
                }
            }

            foreach (var elem in toRemove)
            {
                MapElements.Remove(elem);
            }

            foreach (IDisposable disposable in toRemove.OfType<IDisposable>())
            {
                disposable.Dispose();
            }
        }

        public override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);
            
            foreach (DrawableEscapeGameComponent elem in MapElements.OfType<DrawableEscapeGameComponent>().Where(component => component.Visible))
            {
                elem.Draw(gameTime);
            }

            foreach (var colorable in MapElements.OfType<IColorable>())
            {
                Game.Drawer.DrawRectangle(colorable.Rect, colorable.Color);
            }

            foreach (var sprite in MapElements.OfType<ISprite>())
            {
                Game.SpriteBatch.Draw(sprite.Sprite, sprite.Position, Color.White);
            }
        }

        public bool IntersectsWall(Rectangle rect)
        {
            return MapElements.OfType<Wall>().Any(wall => wall.Rect.Intersects(rect));
        }

        public bool IsInGoalZone(Rectangle rect)
        {
            return goalZone != null && goalZone.Rect.Intersects(rect);
        }
    }
}
